package com.aliyun.service.impl;

import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.PutObjectRequest;

import com.aliyun.pojo.oss.AliyunOss;
import com.aliyun.pojo.AliyunAuthentication;
import com.aliyun.pojo.AliyunMediaDetail;
import com.aliyun.service.AbstractAliyunMediaService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 阿里云 存储服务
 */
@Slf4j
public class AliyunOssService extends AbstractAliyunMediaService {

    @Resource(name = "aliyunThreadPoolExecutor")
    ThreadPoolExecutor aliyunThreadPoolExecutor;

    @Resource
    AliyunCredentialsService aliyunCredentialsService;


    private OSS createClient(AliyunOss aliyunOss){
        AliyunAuthentication aliyunAuthentication = aliyunCredentialsService.tryGetStsAuthorization(aliyunOss.getStsauthorization());
        return new OSSClientBuilder().build(aliyunOss.getEndpoint(), aliyunAuthentication.getAccessKeyId(), aliyunAuthentication.getAccessKeySecret(), aliyunAuthentication.getSecurityToken());
    }

    public AliyunMediaDetail upload(String path) {
        if (StrUtil.isEmpty(path)){
            throw new IllegalArgumentException("上传文件路径不能为空");
        }
        return upload(new File(path));
    }

    public AliyunMediaDetail upload(File file) {
        Assert.notNull(file, "上传文件不能为空");
        try {
            String originFileName = file.getName();
            InputStream inputStream = new FileInputStream(file);
            return upload(inputStream, originFileName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public AliyunMediaDetail multipartUpload(String path) {
        return null;
    }

    public AliyunMediaDetail multipartUpload(File file) {
        return null;
    }

    public void save(String bucket, String objectName, String path) {
        if (StrUtil.isEmptyIfStr(path)){
            throw new IllegalArgumentException("保存文件路径不能为空");
        }
        save(bucket, objectName, new File(path));
    }

    /**
     * 下载文件到本地 指定路径
     *
     * @param bucket     指定要下载文件的桶
     * @param objectName 指定要下载的文件全路径 不包含桶
     * @param path       指定要下载的文件保存路径
     */
    public void save(String bucket, String objectName, File path) {
        OSS ossClient = createClient(aliyunCredentialsService.getOss());
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, objectName);
        ossClient.getObject(getObjectRequest, path);
        log.info("文件下载成功: path: {}", path);
    }


    /**
     * 删除文件
     *
     * @param bucket     指定要删除文件的桶
     * @param objectName 指定要删除的文件全路径 不包含桶
     */
    public void delete(String bucket, String objectName) {
        OSS ossClient = createClient(aliyunCredentialsService.getOss());
        ossClient.deleteObject(bucket, objectName);
        log.warn("删除指定文件成功：bucket:{} object:{}", bucket, objectName);
    }

    public void delete(String bucket, List<String> objectNames) {

    }


    /**
     * 上传文件对象
     * @param inputStream 文件流
     * @param originalFilename 文件原始名称
     */
    public AliyunMediaDetail upload(InputStream inputStream, String originalFilename) throws IOException {
        // 将文件下载到本地
        File loadFile = download(inputStream);
        // 获取Oss配置信息
        AliyunOss aliyunOss = aliyunCredentialsService.getOss();
        OSS ossClient = createClient(aliyunOss);
        // 获取文件后缀
        String suffix = this.getFileSuffix(originalFilename);
        // 获取文件类型
        String fileContentType = this.getFileContentType(suffix);
        // 根据文件类型获取对应的bucket
        String bucket = this.getBucket(fileContentType);
        // 判断bucket是否存在
        if (!ossClient.doesBucketExist(bucket)){
            // 不存在 则创建bucket
            ossClient.createBucket(bucket);
        }
        // 组合为新的ObjectName
        String fileName = UUID.randomUUID() + suffix;
        String objectName = getDirectory() + fileName;
        // 上传文件
        PutObjectRequest request = new PutObjectRequest(bucket,objectName,loadFile);
        ossClient.putObject(request);
        // 校验文件完整性
        // 创建一个临时文件
        File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".temp");
        // 将上传后的文件保存到 tempFile 文件里
        save(bucket, objectName, tempFile);
        // 原始文件流
        InputStream originalStream = new FileInputStream(loadFile);
        // 目标文件流
        InputStream targetStream = new FileInputStream(tempFile);
        AliyunMediaDetail aliyunMediaDetail = new AliyunMediaDetail();
        String validateMd5 = validateFileIntegrity(originalStream, targetStream);
        if (validateMd5 != null) {
            log.debug("文件校验成功=》上传成功 url: {}", objectName);
            aliyunMediaDetail.setUrl(objectName);
            // https://BucketName.Endpoint/ObjectName
            aliyunMediaDetail.setUrl("https://" + bucket + "." + aliyunOss.getEndpoint() + "/" + objectName);
            aliyunMediaDetail.setMd5(validateMd5);
            aliyunMediaDetail.setOriginFileName(fileName);
            aliyunMediaDetail.setBucket(bucket);
            aliyunMediaDetail.setContentType(fileContentType);
        } else {
            log.error("文件校验失败=》上传失败 url: {}", objectName);
            this.delete(bucket, objectName);
            aliyunMediaDetail = null;
        }
        // 5: 删除本地文件
        aliyunThreadPoolExecutor.execute(() -> {
            tempFile.delete();
            loadFile.delete();
        });
        return aliyunMediaDetail;
    }





    /**
     * 当bucket为私有时 生成临时签名URL访问资源
     * @param bucket 桶
     * @param objectName 文件存储路径
     * @param expireHours 签名URL过期小时
     * @return 签名URL
     */
    public String getTempSignUrl(String bucket, String objectName , int expireHours){
        OSS ossClient = createClient(aliyunCredentialsService.getOss());
        return ossClient.generatePresignedUrl(bucket,objectName , new Date(System.currentTimeMillis() + 1000L * 60 * 60 * expireHours)).toString();
    }

    /**
     * 根据文件类型获取对应的bucket
     *
     * @param contentType 文件类型
     * @return bucket
     */
    public String getBucket(String contentType) {
        // 获取文件类型的前缀
        String prex = contentType.split("/")[0];
        Map<String, String> bucketMap = aliyunCredentialsService.getOss().getBuckets();
        boolean contained = bucketMap.containsKey(prex);
        if (contained) {
            return bucketMap.get(prex);
        } else {
            return aliyunCredentialsService.getOss().getDefaultBucket();
        }
    }


}
